package org.rx;

import java.util.ArrayList;

import org.rx.SXPNumbering.Abstract;
import org.rx.SXPNumbering.Concrete;
import org.rx.SXPNumbering.Node;
import org.rx.SXPNumbering.Root;

public class Hierarchy {
	
	static ArrayList<Concrete> concretes = new ArrayList<Concrete>();
	static ArrayList<Abstract> abstracts = new ArrayList<Abstract>();
	
	static Abstract any = new Root("Any", null);
	
	static Abstract atom = new Abstract("Atom", any);
	static Concrete s_atom = new Concrete("Symbol", atom);
	static Concrete s_prom = new Concrete("Promise", atom);
	static Abstract ref = new Abstract("Ref", atom);
	static Concrete s_extptr = new Concrete("EPtr", ref);
	static Concrete s_weakref = new Concrete("WRef", ref);
	static Abstract cons = new Abstract("Cons", atom);
	static Concrete s_list = new Concrete("List", cons);
	static Concrete s_s4 = new Concrete("S4", cons);
	static Abstract lambda = new Abstract("Lambda", atom);
	static Concrete s_closure = new Concrete("Closure", lambda);
	static Concrete s_builtin = new Concrete("Builtin", lambda);
	static Concrete s_special = new Concrete("Special", lambda);

	static Abstract array = new Abstract("Array", any);
	static Concrete s_raw = new Concrete("Raw", array);
	static Concrete s_env = new Concrete("Environment", array);
	static Concrete s_lgl = new Concrete("Logical", array);

	static Abstract number = new Abstract("Number", array);
	static Concrete s_int = new Concrete("Int", number);
	static Concrete s_double = new Concrete("Double", number);
	static Concrete s_complex = new Concrete("Complex", number);
	
	static Concrete s_string = new Concrete("String", array);
	static Concrete s_vector = new Concrete("Vector", array);
	static Concrete s_expression = new Concrete("Expression", array);
	
	static Node hierarchy = Hierarchy.any;			

	static Node toNode(String text){
		for(Node node: concretes)
			if(node.name.equals(text))
				return node;
		for(Node node: abstracts)
			if(node.name.equals(text))
				return node;
		return null;
	};
	
	static int discriminantsBits(int nbs[]){
		int and = nbs[0], or = nbs[0];
		for(int i = 1; i < nbs.length; i++){
			and &= nbs[i];
			or |= nbs[i];
		}
		return and ^ or;
	}
	
	public static int rightMost1Bit(int n){
	   return log2(n&-n)+1;
	}
	
	static int nbOnes(int nb){
		return (1 << nb) - 1; 
	}
	
	static int nbBits(int nb){
		if(nb == 0 || nb == 1)
			return 1;
		return (int)Math.ceil(Math.log(nb) / Math.log(2));
	}
	
	static public int log2(int nb){
		int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
		int S[] = {1, 2, 4, 8, 16};
		int i;

		int r = 0;
		for(i = 4; i >= 0; i--)
			if((nb & b[i]) != 0){
				nb >>= S[i];
				r |= S[i];
			} 
		return r;
	}
}
